// Copyright (c) Microsoft Corporation. All rights reserved.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Xml.XPath;

namespace Microsoft.TeamFoundation.Migration.Toolkit.Wit
{
    /// <summary>
    /// Factory class.
    /// </summary>
    public class WorkItemTrackingConfigurationFactory : IConfigFactory
    {
        /// <summary>
        /// Instantiates the class.
        /// </summary>
        /// <param name="xmlFragment">Initialization XML</param>
        /// <returns>Factory object</returns>        
        public object CreateInstance(Type type, string xmlFragment)
        {
            if (type == typeof(IMigrationProvider))
            {
                using (StringReader reader = new StringReader(xmlFragment))
                {
                    XPathDocument doc = new XPathDocument(reader);
                    return WorkItemTrackingConfiguration.Load(doc.CreateNavigator());
                }
            }

            return null;
        }
    }

    /// <summary>
    /// Provides access to WIT configuration settings
    /// </summary>
    public class WorkItemTrackingConfiguration : SettingsSection, IMigrationProvider
    {
        private Dictionary<string, WorkItemTrackingSession> m_sessions;     // All sessions
        private Dictionary<string, FieldMap> m_fieldMaps;                   // All field maps
        private Dictionary<string, ValueMap> m_valueMaps;                   // All value maps

        /// <summary>
        /// Creates object from the XML.
        /// </summary>
        /// <param name="node">Navigator object pointing to the node</param>
        /// <returns>Configuration object</returns>
        public static WorkItemTrackingConfiguration Load(XPathNavigator node)
        {
            if (node == null)
            {
                throw new ArgumentNullException("node");
            }

            WorkItemTrackingConfiguration config = new WorkItemTrackingConfiguration();
            XPathNavigator witElement = node.Select("/Migration/WIT").Current;

            config.Init(witElement);

            // Load settings
            config.InitFromXml(witElement.Select("/WIT/Settings/Setting"));

            return config;
        }

        /// <summary>
        /// All sessions.
        /// </summary>
        public Dictionary<string, WorkItemTrackingSession> Sessions { get { return m_sessions; } }

        /// <summary>
        /// All field maps.
        /// </summary>
        public Dictionary<string, FieldMap> FieldMaps { get { return m_fieldMaps; } }

        /// <summary>
        /// All value maps.
        /// </summary>
        public Dictionary<string, ValueMap> ValueMaps { get { return m_valueMaps; } }


        #region IMigrationProvider Members

        public void Start()
        {
            foreach (WorkItemTrackingSession session in m_sessions.Values)
            {
                session.Start();
            }
        }

        public void Stop()
        {
            foreach (IMigrationSession session in this.Sessions.Values)
            {
                session.Stop();
            }
        }

        public void Pause()
        {
            foreach (WorkItemTrackingSession session in m_sessions.Values)
            {
                session.Pause();
            }
        }

        public void Resume()
        {
            foreach (WorkItemTrackingSession session in m_sessions.Values)
            {
                session.Resume();
            }
        }

        public void Abort()
        {
            foreach (WorkItemTrackingSession session in m_sessions.Values)
            {
                session.Abort();
            }
        }


        public void Synchronize(SystemType primarySystem)
        {
            foreach (WorkItemTrackingSession session in m_sessions.Values)
            {
                session.Synchronize(primarySystem);
            }
        }

       public void SynchronizeFull()
        {
            foreach (WorkItemTrackingSession session in m_sessions.Values)
            {
                session.SynchronizeFull();
            }
        }

        #endregion

        #region IDisposable Members

        protected virtual void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if (disposing)
                {
                    // dispose managed resources
                    foreach (IMigrationSession s in m_sessions.Values)
                    {
                        s.Dispose();
                    }
                }

                // release unmanged resources
            }

            disposed = true;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        bool disposed;

        #endregion


        /// <summary>
        /// Constructor.
        /// </summary>
        private WorkItemTrackingConfiguration()
        {
            m_sessions = new Dictionary<string, WorkItemTrackingSession>(StringComparer.OrdinalIgnoreCase);
            m_fieldMaps = new Dictionary<string, FieldMap>(StringComparer.OrdinalIgnoreCase);
            m_valueMaps = new Dictionary<string, ValueMap>(StringComparer.OrdinalIgnoreCase);
        }

        /// <summary>
        /// Loads object from the XML document.
        /// </summary>
        /// <param name="nav">Navigator</param>
        private void Init(
            XPathNavigator nav)
        {
            // Field maps
            XPathNodeIterator set = nav.Select("/WIT/FieldMaps/FieldMap");
            foreach (XPathNavigator itemXml in set)
            {
                FieldMap map = new FieldMap(itemXml);
                m_fieldMaps.Add(map.Name, map);
            }
            
            // Value maps
            m_valueMaps = new Dictionary<string, ValueMap>(StringComparer.OrdinalIgnoreCase);
            set = nav.Select("/WIT/ValueMaps/ValueMap");
            foreach (XPathNavigator itemXml in set)
            {
                ValueMap map = new ValueMap(itemXml);
                m_valueMaps.Add(map.Name, map);
            }

            // Sessions.
            set = nav.Select("/WIT/Sessions/Session");
            foreach (XPathNavigator itemXml in set)
            {
                WorkItemTrackingSession session = WorkItemTrackingSession.Load(itemXml);
                m_sessions.Add(session.Id, session);
            }

        }

        public override void RegisterParent(ISettingsSection parent)
        {
            base.RegisterParent(parent);

            foreach (WorkItemTrackingSession session in m_sessions.Values)
            {
                session.RegisterParent(this);
            }
        }
    }
}
